#include "softI2c.h"
#include "delay.h"

void i2cInit(void) {
    // 使能 GPIOH 时钟
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOHEN;
    // 配置 PH4
    GPIOH->MODER &= ~(GPIO_MODER_MODE4_Msk); // 清除 PH4 的模式位
    GPIOH->MODER |= GPIO_MODER_MODE4_0; // 设置 PH4 为输出模式（01）
    GPIOH->OTYPER &= ~(GPIO_OTYPER_OT_4); // 设置 PH4 为推挽输出（0）
    GPIOH->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED4_Msk); // 清除 PH4 的速度位
    GPIOH->OSPEEDR |= GPIO_OSPEEDR_OSPEED4_1; // 设置 PH4 为高速模式（10）
    GPIOH->PUPDR &= ~(GPIO_PUPDR_PUPD4_Msk); // 清除 PH4 的上拉/下拉位
    // 配置 PH5
    GPIOH->MODER &= ~(GPIO_MODER_MODE5_Msk); // 清除 PH5 的模式位
    GPIOH->MODER |= GPIO_MODER_MODE5_0; // 设置 PH5 为输出模式（01）
    GPIOH->OTYPER &= ~(GPIO_OTYPER_OT_5); // 设置 PH5 为推挽输出（0）
    GPIOH->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEED5_Msk); // 清除 PH5 的速度位
    GPIOH->OSPEEDR |= GPIO_OSPEEDR_OSPEED5_1; // 设置 PH5 为高速模式（10）
    GPIOH->PUPDR &= ~(GPIO_PUPDR_PUPD5_Msk); // 清除 PH5 的上拉/下拉位
    GPIOH->ODR |= (GPIO_ODR_OD4|GPIO_ODR_OD5); // 设置 PH4 PH5 为高电平
}

// 产生I2C起始信号
void i2cStart(void) {
    SDA_OUT(); // sda线输出
    IIC_SDA(1);
    IIC_SCL(1);
    delay_us(4);
    IIC_SDA(0); // START:when CLK is high,DATA change from high to low
    delay_us(4);
    IIC_SCL(0); // 钳住I2C总线,准备发送或接收数据
}

// 产生IIC停止信号
void i2cStop(void) {
    SDA_OUT(); // sda线输出
    IIC_SCL(0);
    IIC_SDA(0); // STOP:when CLK is high,DATA change from low to high
    delay_us(4);
    IIC_SCL(1);
    IIC_SDA(1); // 发送I2C总线结束信号
    delay_us(4);
}

// 等待应答信号到来
// 返回值:1.接收应答失败 0.接收应答成功
uint8_t i2cWaitAck(void) {
    uint8_t ucErrTime = 0;
    SDA_IN(); // 设置SDA为输入
    IIC_SDA(1);delay_us(1);
    IIC_SCL(1);delay_us(1);
    while (READ_SDA) {
        ucErrTime++;
        if(ucErrTime >250) {
            i2cStop();
            return 1;
        }
    }
    IIC_SCL(0); // 时钟输出0
    return 0;
}

//产生ACK应答
void i2cAck(void) {
    IIC_SCL(0);
    SDA_OUT();
    IIC_SDA(0);
    delay_us(2);
    IIC_SCL(1);
    delay_us(2);
    IIC_SCL(0);
}

//不产生ACK应答
void i2cNAck(void) {
    IIC_SCL(0);
    SDA_OUT();
    IIC_SDA(1);
    delay_us(2);
    IIC_SCL(1);
    delay_us(2);
    IIC_SCL(0);
}

//IIC发送一个字节
//返回从机有无应答
//1，有应答
//0，无应答
void i2cSendByte(uint8_t txd) {
    uint8_t t;
    SDA_OUT();
    IIC_SCL(0); // 拉低时钟开始数据传输
    for(t=0; t<8; t++) {
        IIC_SDA((txd&0x80)>>7);
        txd<<=1;
        delay_us(2);   //对TEA5767这三个延时都是必须的
        IIC_SCL(1);
        delay_us(2);
        IIC_SCL(0);
        delay_us(2);
    }
}

//读1个字节，ack=1时，发送ACK，ack=0，发送nACK
uint8_t i2cReadByte(uint8_t ack) {
    uint8_t i,receive=0;
    SDA_IN(); // SDA设置为输入
    for(i=0; i<8; i++) {
        IIC_SCL(0);
        delay_us(2);
        IIC_SCL(1);
        receive<<=1;
        if(READ_SDA)receive++;
        delay_us(1);
    }
    if (!ack)
        i2cNAck();//发送nACK
    else
        i2cAck(); //发送ACK
    return receive;
}
